﻿using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Xml;
using LinFu.IoC.Configuration;

namespace CoreEx.ServiceModel.Implementation
{
    [Implements(typeof(XmlObjectSerializer), ServiceName = "XmlBinarySerializer")]
    public class XmlBinarySerializer : XmlObjectSerializer
    {
        private readonly BinaryFormatter _binaryFormatter = new BinaryFormatter();
        
        private const string BinaryElement = "BinaryElement";
        
        public override void WriteStartObject(XmlDictionaryWriter writer, object graph)
        {
            writer.WriteStartElement(BinaryElement);
        }

        public override void WriteObjectContent(XmlDictionaryWriter writer, object graph)
        {
            if (graph == null)
                graph = new NullValue();

            using (var ms = new MemoryStream())
            {
                _binaryFormatter.Serialize(ms, graph);
                byte[] buffer = ms.GetBuffer();
                writer.WriteBase64(buffer, 0, (int)ms.Length);
            }
            
        }

        public override void WriteEndObject(XmlDictionaryWriter writer)
        {
            writer.WriteEndElement();
        }

        public override object ReadObject(XmlDictionaryReader reader, bool verifyObjectName)
        {            
            reader.ReadStartElement(BinaryElement);
            try
            {
                using (var ms = new MemoryStream(reader.ReadContentAsBase64()))
                {
                    object val = _binaryFormatter.Deserialize(ms);
                    if (val is NullValue)
                        return null;
                    return val;
                }
            }
            finally
            {
                reader.ReadEndElement();
            }
        }

        public override bool IsStartObject(XmlDictionaryReader reader)
        {
            return reader.NodeType == XmlNodeType.Element && reader.Name == BinaryElement;
        }
    }
}
